﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml.Linq;

namespace Bing
{
    /// <summary>
    /// This class contains:
    /// <ul>
    /// <li>An array of results returned for a request to the News <see cref="ApiHelper.SourceType"/></li>
    /// <li>An array of array of results containing <see cref="NewsArticle.Title" />s and <see cref="NewsArticle.Url" />s that Bing suggests may be related to the query terms for the request</li>
    /// <li>Properties indicating total number and positioning of results.</li>
    /// </ul>
    /// </summary>
    [DebuggerDisplay("Total={Total}, Results={Results.Count}, Errors={Errors.Count}")]
    public class NewsResponse: SearchResponseBase
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="NewsResponse"/> class.
        /// </summary>
        public NewsResponse(XContainer element)
            : base(element)
        {
            Results = new List<NewsResult>();
            RelatedSearches = new List<NewsRelatedSearch>();
        }

        /// <summary>
        /// Gets or sets the actual offset, from zero, for the starting point of the result set that is returned from the corresponding <see cref="NewsRequest"/>.
        /// </summary>
        /// <value>Returns the actual offset, from zero, for the starting point of the
        /// result set that is returned from the corresponding <see cref="NewsRequest"/>.</value>
        public UInt32 Offset { get; set; }

        // TODO: Documentation Error: http://msdn.microsoft.com/en-us/library/dd250926.aspx, the Remarks contain a property NewsRequest.Count that does not exists.
        /// <summary>
        /// Gets or sets the number that represents an estimate of the total number of results returned by the <see cref="NewsRequest"/>. The default number of results per response is 10.
        /// </summary>
        /// <value>Returns a number that represents an estimate of the total number of results returned by the <see cref="NewsRequest"/>. The default number of results per response is 10.</value>
        /// <remarks>
        /// Based on a number of technical reasons, which are beyond the scope of this documentation, the Bing Engine does not return an exact total for a <see cref="NewsRequest"/>.<br />
        /// If the number of results remaining is less than the number requested, the Bing Engine returns the remaining results without error.<br />
        /// Note: This property is only applicable when a value is sent for <see cref="SearchRequest.Query" />.<br />
        /// </remarks>
        public UInt32 Total { get; set; }

        // TODO: Documentation Error: http://msdn.microsoft.com/en-us/library/dd251052.aspx, summary should list NewsRelatedSearch not RelatedSearch.
        /// <summary>
        /// Gets or sets a List of <see cref="NewsRelatedSearch"/> results returned for this <see cref="NewsRequest"/>.
        /// </summary>
        /// <value>List of <see cref="NewsRelatedSearch"/> results returned for this <see cref="NewsRequest"/>.</value>
        public List<NewsRelatedSearch> RelatedSearches { get; set; }

        /// <summary>
        /// Gets or sets List of results returned for this <see cref="NewsRequest"/>.
        /// </summary>
        /// <value>List of results returned for this <see cref="NewsRequest"/>.</value>
        public List<NewsResult> Results { get; set; }

        /// <summary>
        /// Parses the response from the Bing API.
        /// </summary>
        /// <param name="element">The XML from the Bing API</param>
        /// <returns>An <see cref="NewsResponse" /></returns>
        public static NewsResponse ParseElement(XContainer element)
        {
            NewsResponse newsResponse = new NewsResponse(element);
            if (newsResponse.Errors.Count > 0) return newsResponse;

            var news = element.Element(XName.Get("News", ApiHelper.NewsNs));
            if (news == null) return newsResponse;

            newsResponse.Total = ApiHelper.GetElementValueOrDefault<UInt32>(news, "Total", ApiHelper.NewsNs);
            newsResponse.Offset = ApiHelper.GetElementValueOrDefault<UInt32>(news, "Offset", ApiHelper.NewsNs);

            XElement newsResults = news.Element(XName.Get("Results", ApiHelper.NewsNs));
            if (newsResults != null)
            {
                foreach (XElement result in newsResults.Elements(XName.Get("NewsResult", ApiHelper.NewsNs)))
                {
                    newsResponse.Results.Add(new NewsResult(result));
                }
            }

            XElement relatedSearchesResults = news.Element(XName.Get("RelatedSearches", ApiHelper.NewsNs));
            if (relatedSearchesResults != null)
            {
                foreach (
                    XElement result in
                        relatedSearchesResults.Elements(XName.Get("NewsRelatedSearch", ApiHelper.NewsNs)))
                {
                    newsResponse.RelatedSearches.Add(new NewsRelatedSearch(result));
                }
            }

            return newsResponse;
        }
    }
}
